package com.biodiv.miracle.aop.proxy;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.List;

/**
 * @Author: tianquan
 * @date: 2024-10-09  20:39
 * @Description: 代理工厂类，用于生成代理对象
 */
public class PoxyFactory {

    /**
     * 获取代理对象的方法
     *
     * @param object 需要被代理的对象
     * @param objectMethodName 需要被代理的方法名列表
     * @param beforeMethod 在目标方法执行前执行的方法
     * @param aroundMethod 在目标方法执行前后执行的方法
     * @param afterMethod 在目标方法执行后执行的方法
     * @param target 目标对象
     * @return 返回代理对象
     */
    public static Object getProxy(Object object, List<String> objectMethodName, Method beforeMethod,
                                  Method aroundMethod, Method afterMethod, Object target) {
        try {
            // 根据代理类型创建并返回代理对象
            return ((MethodInvocation) getProxyType(object)
                    .newInstance(object, objectMethodName, beforeMethod, aroundMethod, afterMethod, target))
                    .getProxy();
        } catch (Throwable e) {
            // 将任何异常转换为RuntimeException抛出
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取适当的代理类型构造器
     *
     * @param object 需要被代理的对象
     * @return 返回代理类型的构造器
     */
    private static Constructor<?> getProxyType(Object object) {

        // 判断需要使用什么代理模式
        if (object.getClass().getInterfaces().length >= 1) {
            // 如果对象实现了接口，则使用JDK动态代理
            try {
                return JdkProxyHandler.class.getConstructor(Object.class, List.class, Method.class,
                        Method.class, Method.class, Object.class);
            } catch (NoSuchMethodException e) {
                throw new RuntimeException(e);
            }
        } else {
            try {
                // 使用byte-buddy代理
                return ByteBuddyProxyHandler.class.getConstructor(Object.class, List.class, Method.class,
                        Method.class, Method.class, Object.class);
                // 使用CGLIB代理
                // return CglibMethodInvocation.class.getConstructor(Object.class, List.class, Method.class,
                //         Method.class, Method.class, Object.class);
            } catch (NoSuchMethodException e) {
                throw new RuntimeException(e);
            }
        }
    }


}





